﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;

public class SocketTcp : MonoBehaviour
{
    private static SocketTcp _instance;

    //TCPClient
    private TcpClient _tcpClient;
    private NetworkStream _netStream;//得到网络流

    //接收处理类
    public class TransData
    {
        public TransData(Action<bool, string> action, int buffsize = 8192)
        {
            recvbuff = new byte[1000000];
            tmpbuff = new byte[buffsize];
            istrans = false;
            actionResult = action;
            recvsize = 0;
        }

        public byte[] tmpbuff;
        public byte[] recvbuff;
        public int recvsize;
        public bool istrans;
        public Action<bool, string> actionResult;
    }

    private string _ipadr;
    private int _port;

    public static SocketTcp Instance
    {
        get
        {
            if (_instance == null)
            {
                GameObject goRestful = new GameObject("SocketTcp");
                _instance = goRestful.AddComponent<SocketTcp>();
            }
            return _instance;
        }
    }

    public SocketTcp Connect(string ipadr, int port)
    {
        _ipadr = ipadr;
        _port = port;
        try
        {
            if (_tcpClient == null || !_tcpClient.Connected)
            {
                _tcpClient = new TcpClient(_ipadr, _port);
                _tcpClient.ReceiveBufferSize = 8192;
                _tcpClient.SendBufferSize = 8192;
                _netStream = _tcpClient.GetStream();
            }
        }
        catch (System.Exception)
        {
            _tcpClient.Close();
            _tcpClient.Dispose();
            Connect(ipadr, port);
        }
        return Instance;
    }


    public SocketTcp Send(string msg = "")
    {
        try
        {
            if (_netStream.CanWrite)
            {
                Byte[] sendBytes = Encoding.UTF8.GetBytes(msg);
                _netStream.Write(sendBytes, 0, sendBytes.Length);
                _netStream.Flush();
            }
        }
        catch (System.Exception)
        {
            _tcpClient.Close();
            _tcpClient.Dispose();
            Connect(_ipadr, _port).Send(msg);
        }
        return Instance;
    }

    public SocketTcp Recv(Action<bool, string> action = null)
    {
        TransData trans = new TransData(action, _tcpClient.ReceiveBufferSize);
        try
        {
            _netStream.BeginRead(trans.tmpbuff, 0, trans.tmpbuff.Length,
                TcpDataReceived, trans);
        }
        catch (System.Exception)
        {
            _tcpClient.Close();
            _tcpClient.Dispose();
            Connect(_ipadr, _port).Recv(action);
        }
        return Instance;
    }


    private void TcpDataReceived(IAsyncResult ar)
    {
        int recv = 0;
        TransData transData = (TransData)ar.AsyncState;
        try
        {
            recv = _netStream.EndRead(ar);
        }
        catch
        {
            recv = 0;
        }

        //判断接收数为0，并且未在接收中
        if (recv == 0 && !transData.istrans)
        {
            transData = new TransData(transData.actionResult, _tcpClient.ReceiveBufferSize);
            _netStream.BeginRead(transData.tmpbuff, 0, transData.tmpbuff.Length,
                TcpDataReceived, transData);
        }
        //已在接收了，再次接收为0，说明接收完了，直接调用
        else if (recv == 0)
        {
            //执行回调函数
            string resstr = Encoding.UTF8.GetString(transData.recvbuff);
            transData.actionResult(transData.istrans, resstr);
        }
        //如果recv大于0,说明接收到了数据，修改接收值
        else
        {
            transData.istrans = true;

            byte[] buff = new byte[recv];
            Buffer.BlockCopy(transData.tmpbuff, 0, buff, 0, recv);
            Buffer.BlockCopy(buff, 0, transData.recvbuff, transData.recvsize, recv);
            transData.recvsize += recv;

            if (recv < transData.tmpbuff.Length)
            {
                //执行回调函数
                string resstr = Encoding.UTF8.GetString(transData.recvbuff);
                int strlen = resstr.IndexOf('\0');
                if (strlen > 0)
                {
                    resstr = resstr.Substring(0, strlen);
                }
                transData.actionResult(transData.istrans, resstr);
                //执行完回调后重新初始化接收参数
                transData = new TransData(transData.actionResult, _tcpClient.ReceiveBufferSize);
            }

            _netStream.BeginRead(transData.tmpbuff, 0, transData.tmpbuff.Length,
                TcpDataReceived, transData);
        }
    }
}
